
#include <gdt.h>

struct __gdt_entry __gdt[3];
struct __gdt_info __gdt_info;

void _gdt_make_gdt_entry(struct __gdt_entry *entry, unsigned short limit_low,
			 unsigned short base_low, unsigned char base_middle,
			 unsigned char access, unsigned char granularity,
			 unsigned char base_high){

  entry->limit_low = limit_low;
  entry->base_low = base_low;
  entry->base_middle = base_middle;
  entry->access = access;
  entry->granularity = granularity;
  entry->base_high = base_high;

}

void _gdt_set_gdt_info(unsigned int base_addr, unsigned short lim){

  __gdt_info.base = base_addr;
  __gdt_info.limit = lim;

}

void _gdt_make_basic_gdt(){

  /* First entry set to zero. */
  _gdt_make_gdt_entry(&__gdt[0], 0, 0, 0, 0, 0, 0);

  /* Only make two real entries, a code segment and a data segment. */
  unsigned short lim_low = 0xFFFF;
  unsigned char lim_high = 0x0F;
  unsigned short base_low = 0;
  unsigned char base_mid = 0;
  unsigned char access = (__GDT_PRESENT | __GDT_TYPE);
  unsigned char granularity = (__GDT_4K_GRAN | __GDT_32BIT | lim_high);
  unsigned char base_high = 0;

  _gdt_make_gdt_entry(&(__gdt[1]), lim_low, base_low, base_mid, 
		      (access | __GDT_CODE_RW), granularity, base_high);
  _gdt_make_gdt_entry(&(__gdt[2]), lim_low, base_low, base_mid, 
		      (access | __GDT_DATA_RW), granularity, base_high);

  _gdt_print_gdt_desc(1);
  _gdt_print_gdt_desc(2);
  _gdt_set_gdt_info((unsigned int)&__gdt, 23);
  _gdt_print_gdtr();

  _flush_gdt();

}

void _gdt_print_gdt_desc(unsigned int entry){

  unsigned int *gdte_low = (unsigned int *) &(__gdt[entry]);
  char buf[33];
  itobs(*(gdte_low + 1), buf);
  k_print("high 32 bits: ");
  k_print(buf);

  itobs(*gdte_low, buf);
  k_print("\n low 32 bits: ");
  k_print(buf);
  k_printl();

}

struct __gdt_info gdt_tmp;

void _gdt_print_gdtr(){

  //_store_gdt();
  gdt_tmp = __gdt_info;
  char buf[33];
  itobs(gdt_tmp.base, buf);
  k_print("base address: ");
  k_print(buf);

  itobs((unsigned int) gdt_tmp.limit, buf);
  k_print("\n       limit: ");
  k_print(buf);
  k_printl();

}
